﻿using CommonExtenControl;
using CommonExtenControl.Enum;
using CommonExtenControl.Model;
using CommonExtenControl.Model.Base;
using CustomControls.PoptipCtr;
using LogProjectManager;
using ManagementTool.BaseViewModels;
using ManagementTool.Config;
using ManagementTool.DB.Control;
using ManagementTool.DB.Model;
using ManagementTool.DB.Sql;
using Microsoft.Win32;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Prism.Services.Dialogs;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Interop;

namespace ManagementTool.NetWorks
{
    public class RecvDateModel 
    {
        public string CientMsg { set; get; }

        public string ClientEndPoint { set; get; }
    }

    public class SocketControl
    {
        #region 
        string RemoteEndPoint;

        private ConcurrentQueue<RecvDateModel> MesgList { set; get; }

        Socket socketwatch = null;

        Dictionary<string, Socket> dic1 = new Dictionary<string, Socket> { };


        Dictionary<string, string> ClientList = new Dictionary<string, string> { };
        string recStr = null;
        #endregion

        public void InitServerDate()
        {
            MesgList=new ConcurrentQueue<RecvDateModel>();
            RunRecveMsg();
            InitSocket();
            
        }

        public void InitSocket()
        {
            try
            {
                string _File = AppDomain.CurrentDomain.BaseDirectory + "\\Config\\MyConfigModel.json";
                if (File.Exists(_File))
                {
                    string StrCotent = File.ReadAllText(_File);
                    MyConfigModel itemModel = JsonConvert.DeserializeObject<MyConfigModel>(StrCotent);
                    if (itemModel != null)
                    {
                        //定义一个套接字用于监听客户端发来的消息，包含三个参数（IP4寻址协议，流式连接，Tcp协议）
                        socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        //服务端发送信息需要一个IP地址和端口号
                        IPAddress address = IPAddress.Parse(itemModel.SocketServerAddress);//获取文本框输入的IP地址

                        IPEndPoint point = new IPEndPoint(address, int.Parse(itemModel.SocketServerPort));//获取文本框上输入的端口号            //此端口专门用来监听的

                        //监听绑定的网络节点
                        socketwatch.Bind(point);
                        //将套接字的监听队列长度限制为20
                        socketwatch.Listen(100000);
                        WatchConnecting();
                    }
                }

            }
            catch (Exception ex)
            {
         
            }
        }

        public Socket SendMsg(string TagetClientPoint, string Msg, byte symbol, OperationType _itemType= OperationType.Other, string _backClientPoint = "") 
        {
            Socket _ClientSocket = null;
            try
            {               
                if (dic1.Count>0)
                {
                    if (dic1.Keys.Contains(TagetClientPoint))
                    {
                        var newBuffer = GetSendByte(Msg, symbol);
                        var itemSocket = dic1[TagetClientPoint];
                        itemSocket.Send(newBuffer);
                        _ClientSocket = itemSocket;
                        SendBackMsg(_itemType, _backClientPoint);
                    }
                    else if (dic1.Keys.Contains(_backClientPoint))
                    {
                        SendBackMsg(_itemType, _backClientPoint,false);
                    }

                }         
            }
            catch (Exception ex) 
            {
                SendBackMsg(_itemType, _backClientPoint,false);
            }
            return _ClientSocket;
        }

        private void SendBackMsg(OperationType _ItemType,string _backclientPoint = "", bool isSuccess = true) 
        {
            try
            {
                //if (!string.IsNullOrEmpty(_backclientPoint))
                //{
                //    var itemModel = new CommonExtenControl.Model.DeviceModel();
                //    itemModel.CurrentOperationType = _ItemType;
                //    itemModel.RecvDataTypeModel = CommonPropertyDefin.BackMsgCommand;
                //    itemModel.CurrentOperationResultTypee = isSuccess? OperationResultType.Success: OperationResultType.Error;
                //    string strMsg = JsonConvert.SerializeObject(itemModel);
                //    var newBufferBack = GetSendByte(strMsg, 0);
                //    var adminClient = dic1[_backclientPoint];
                //    adminClient.Send(newBufferBack);
                //}
            }
            catch (Exception ex) 
            {
              
            }
        }

        private void SendBackCmd() 
        {
            try
            {
                //var itemModel = new DeviceModel();
                //itemModel.RecvDataTypeModel = CommonPropertyDefin.BackLoadDateCommand;
                //string strMsg = JsonConvert.SerializeObject(itemModel);
                //var newBufferBack = GetSendByte(strMsg, 0);
                //foreach (var item in dic1.Values)
                //{
                //    item.Send(newBufferBack);
                //}
            }
            catch (Exception ex)
            {

            }
        }


        private byte[] GetSendByte(string Msg, byte symbol) 
        {
            byte[] buffer = Encoding.UTF8.GetBytes(Msg);

            byte[] newBuffer = new byte[buffer.Length + 1];

            newBuffer[0] = symbol;

            Buffer.BlockCopy(buffer, 0, newBuffer, 1, buffer.Length);
            return newBuffer;
        }

        private void SendFile(string fileFullPath,string fileName, string _tagetclientPoint, string _backclientPoint = "")
        {
            long fileLength = new FileInfo(fileFullPath).Length;
            string totalMsg = string.Format("{0}-{1}", fileName, fileLength);
            Socket client_Socket=SendMsg(_tagetclientPoint, totalMsg, 2);
            if (client_Socket!=null) 
            {
                byte[] buffer = new byte[2 * 1024];
                using (FileStream fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
                {
                    int readLength = 0;
                    bool firstRead = true;
                    long sentFileLength = 0;
                    while ((readLength = fs.Read(buffer, 0, buffer.Length)) > 0 && sentFileLength < fileLength)
                    {
                        sentFileLength += readLength;
                        if (firstRead)
                        {
                            byte[] firstBuffer = new byte[readLength + 1];
                            firstBuffer[0] = 1;
                            Buffer.BlockCopy(buffer, 0, firstBuffer, 1, readLength);
                            client_Socket.Send(firstBuffer, 0, readLength + 1, SocketFlags.None);
                            firstRead = false;
                        }
                        else
                        {
                            client_Socket.Send(buffer, 0, readLength, SocketFlags.None);
                        }
                    }
                    fs.Close();
                }
                SendBackMsg(OperationType.Update, _backclientPoint);
                Console.WriteLine("发送完成");
            }
          
        }
        private void WatchConnecting()
        {
            Task.Run(() => {
                Socket connection = null;
                while (true)  //持续不断监听客户端发来的请求   
                {
                    try
                    {
                        connection = socketwatch.Accept();
                    }
                    catch (Exception ex)
                    {
                       
                        MessageControl.Warning($"套接字监听异常", "RootMessageTooken");
                        break;
                    }
                    //获取客户端的IP和端口号
                    IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
                    int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;

                   
                    RemoteEndPoint = connection.RemoteEndPoint.ToString(); //客户端网络结点号
                    string _strMsg = $"成功与 {RemoteEndPoint} 客户端建立连接！";

                    LogManager.WriteLog(LogTypeEnum.Normal, "WatchConnecting", _strMsg);
              
                    if (!dic1.ContainsKey(RemoteEndPoint)) 
                    {
                        dic1.Add(RemoteEndPoint, connection);    //添加客户端信息
                    }

                    if (!ClientList.ContainsKey(RemoteEndPoint)) 
                    {
                        ClientList.Add(RemoteEndPoint, RemoteEndPoint);
                    }
                   
                     //OnlineList_Disp(RemoteEndPoint);    //显示在线客户端


                     //IPEndPoint netpoint = new IPEndPoint(clientIP,clientPort);

                     IPEndPoint netpoint = connection.RemoteEndPoint as IPEndPoint;

                    //创建一个通信线程    
                    ParameterizedThreadStart pts = new ParameterizedThreadStart(recv);
                    Thread thread = new Thread(pts);
                    thread.IsBackground = true;//设置为后台线程，随着主线程退出而退出   
                                               //启动线程   
                    thread.Start(connection);
                }
            });
        }

        private void RunRecveMsg() 
        {
            //Task.Run(async () => {
            //    while (true) 
            //    {
            //        try 
            //        {
            //            if (MesgList.Count > 0)
            //            {
            //                RecvDateModel itemRecv = null;
            //                bool flg = MesgList.TryDequeue(out itemRecv);
            //                if (flg)
            //                {
            //                    JObject jsonObj = JObject.Parse(itemRecv.CientMsg);
            //                    List<JToken> listJToken = jsonObj.Root.ToList();
            //                    foreach (var item in listJToken) 
            //                    {
            //                        var temp_item = (JProperty)item;
            //                        if (temp_item.Name == "RecvDataTypeModel") 
            //                        {
            //                            if (!string.IsNullOrEmpty(temp_item.Value.ToString())) 
            //                            {
            //                                if (temp_item.Value.ToString() == CommonPropertyDefin.DeviceDateCmd)
            //                                {
            //                                    var itemModel = JsonConvert.DeserializeObject<CommonExtenControl.Model.DeviceModel>(itemRecv.CientMsg);
            //                                    string[] strArry = itemRecv.ClientEndPoint.Split(':');
            //                                    if (strArry.Length > 1)
            //                                    {
            //                                        itemModel.IPAddress = strArry[0];
            //                                        itemModel.Port = strArry[1];
            //                                        string _backClientEndPoint = itemRecv.ClientEndPoint;
            //                                        WriteDevDateToDB(itemModel);
            //                                    }
            //                                }
            //                                else if (temp_item.Value.ToString() == CommonPropertyDefin.AdminCommand)
            //                                {
            //                                    var itemModel = JsonConvert.DeserializeObject<dynamic>(itemRecv.CientMsg);
            //                                    string _Ip = itemModel.IPAddress;
            //                                    string _port = itemModel.Port;
            //                                    string _tagetClientendPoint = _Ip + ":" + _port;
            //                                    string _backClientEndPoint = itemRecv.ClientEndPoint;
            //                                    if (itemModel.CurrentOperationType == OperationType.Update)
            //                                    {
            //                                        string _FPath = itemModel.FilePath + "\\" + itemModel.FileName;
            //                                        string _fileName = itemModel.FileName;
            //                                        SendFile(_FPath, _fileName, _tagetClientendPoint, _backClientEndPoint);
            //                                    }
            //                                    else
            //                                    {
            //                                        OperationType _iteType = itemModel.CurrentOperationType;
                                                   
            //                                        SendMsg(_tagetClientendPoint, itemRecv.CientMsg, 0, _iteType, _backClientEndPoint);
            //                                    }
            //                                }
            //                                else if (temp_item.Value.ToString() == CommonPropertyDefin.FileDateCmd)
            //                                {
            //                                    var itemModel = JsonConvert.DeserializeObject<CommonExtenControl.Model.FileModel>(itemRecv.CientMsg);
            //                                    WriteFileDateToDB(itemModel);
            //                                }
            //                                else if (temp_item.Value.ToString() == CommonPropertyDefin.HeatBeatCmd) 
            //                                {
                                            
            //                                }
            //                            }
            //                        }
            //                    }
                              
                                
            //                }
            //            }
            //        }
            //        catch (Exception ex) 
            //        {
                      
            //        }
                   
                    
            //        await Task.Delay(50);
            //    }
            //});
        }


        //private void WriteDevDateToDB(CommonExtenControl.Model.DeviceModel itemDev)
        //{
        //    try
        //    {
        //        string exitsSql = InstanceBase<SqlsControl>.Instance.GetAnyDevItemSql(itemDev.PcSign);
        //        bool isExits = InstanceBase<MySqlDbControl>.Instance.GetTargetDBIsHaveDate(exitsSql);
        //        string _sql = "";
        //        if (isExits)
        //        {
        //            //Update
        //            _sql = InstanceBase<SqlsControl>.Instance.GetUpdateDevLoginTimeSql(itemDev.PcSign, itemDev);
        //        }
        //        else
        //        {
        //            _sql = InstanceBase<SqlsControl>.Instance.GetInstertDevISql(itemDev);
        //        }
        //        int resultUpdate = InstanceBase<MySqlDbControl>.Instance.ExeCuteCommonSql(_sql);
        //        bool flg = resultUpdate == -1 ? false : true;
        //        if (flg) 
        //        {
        //            SendBackCmd();
        //        }
        //    }
        //    catch (Exception ex) 
        //    {
        //        LogManager.WriteLog(LogTypeEnum.Exception, "WriteDevDateToDB", ex.Message);
        //    }
        //}

        private void WriteFileDateToDB(CommonExtenControl.Model.FileModel itemDev)
        {
            try
            {
                string Sql = InstanceBase<SqlsControl>.Instance.GetInstertFileISql(itemDev);             
                int resultUpdate = InstanceBase<MySqlDbControl>.Instance.ExeCuteCommonSql(Sql);
                string MesgTip = resultUpdate == -1 ? "添加失败" : "添加成功";
               
            }
            catch (Exception ex)
            {
               
            }
        }

        private void recv(object socketclientpara)
        {
            try
            {
                Socket socketServer = socketclientpara as Socket;
                long fileLength = 0; //接收到数据长度
                while (true)
                {
                    int threadID = Thread.CurrentThread.ManagedThreadId;
                    int firstRcv = 0; //字节长度
                    byte[] buffer = new byte[8 * 1024]; //预先申请8K大小的内存缓存区
                    try
                    {
                        if (socketServer != null) //如果当前的套接字不为空 说明是有连接存在
                        {
                            //获取接受数据的长度，存入内存缓冲区，返回一个字节数组的长度
                            firstRcv = socketServer.Receive(buffer);
                        }

                        //判断该数组长度情况
                        if (firstRcv > 0) //说明有数据过来
                        {
                            if (buffer[0] == 0)//0对应文字信息,发消息了
                            {
                                //将机器接受到的字节数组转换为人可以读懂的字符串   
                                recStr = Encoding.UTF8.GetString(buffer, 0, firstRcv);
                                var itemRecv = new RecvDateModel();
                                itemRecv.CientMsg = recStr;
                                itemRecv.ClientEndPoint = socketServer.RemoteEndPoint.ToString();
                                MesgList.Enqueue(itemRecv);
                             
                            }

                            if (buffer[0] == 1) // 说明发文件过来了，不是消息
                            {
                                //SQLServer2008R2SP3-KB2979597-x64-CHS.exe
                                //处理文件名称 去后缀 
                                string filenameSuffix = recStr.Substring(recStr.LastIndexOf("."));

                                string RootFloder = AppDomain.CurrentDomain.BaseDirectory + "\\RecvData";
                                if (!Directory.Exists(RootFloder)) 
                                {
                                    Directory.CreateDirectory(RootFloder);
                                }
                                string ItemP = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
                                string SaveDBPath = "RecvData" + "\\" + ItemP;

                                string ItemFloder = RootFloder + "\\" + ItemP;
                                if (!Directory.Exists(ItemFloder))
                                {
                                    Directory.CreateDirectory(ItemFloder);
                                }
                                string savePath = ItemFloder + "\\" + recStr;
                                int rec = 0;
                                long recFileLength = 0;
                                bool firstWrite = true;
                                using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
                                {
                                    while (recFileLength < fileLength)
                                    {
                                        if (firstWrite)
                                        {
                                            fs.Write(buffer, 1, firstRcv - 1);
                                            fs.Flush();
                                            recFileLength += firstRcv - 1;
                                            firstWrite = false;
                                        }
                                        else
                                        {
                                            rec = socketServer.Receive(buffer);
                                            fs.Write(buffer, 0, rec);
                                            fs.Flush();
                                            recFileLength += rec;
                                        }
                                    }
                                    //接收完毕 关闭流
                                    fs.Close();
                                } //using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
                                string fName = savePath.Substring(savePath.LastIndexOf("\\") + 1);
                                string fPath = savePath.Substring(0, savePath.LastIndexOf("\\"));
                                string strMsg = $"{DateTime.Now}====成功接收了文件... 【\" + fName + \"】";
                                LogManager.WriteLog(LogTypeEnum.Normal, "recv", strMsg);
                                var FileItem = new FileModel();
                                FileItem.RecvDataTypeModel = CommonPropertyDefin.FileDateCmd;
                                FileItem.FileName = fName;
                                FileItem.FilePath = SaveDBPath;
                                FileItem.FileUpdateTime = DateTime.Now;
                                string fileStrMsg=JsonConvert.SerializeObject(FileItem);
                                var itemRecv = new RecvDateModel();
                                itemRecv.CientMsg = fileStrMsg;
                                MesgList.Enqueue(itemRecv);
                            }
                            if (buffer[0] == 2)//2对应文件名字和长度
                            {
                                string fileNameWithLength = Encoding.UTF8.GetString(buffer, 1, firstRcv - 1);
                                //截取最后一个"-" 之前的数据
                                recStr = fileNameWithLength.Substring(0, fileNameWithLength.LastIndexOf('-'));

                                fileLength = Convert.ToInt64(fileNameWithLength.Split('-').Last());
                            }
                            buffer = null;
                        }////说明有数据过来
                    }
                    catch (Exception ex)
                    {
                        LogManager.WriteLog(LogTypeEnum.Exception, "recv", ex.Message);
                        string[] arrayStr = socketServer.RemoteEndPoint.ToString().Split(':');
                        if (ClientList.ContainsKey(arrayStr[0])) 
                        {
                            ClientList.Remove(arrayStr[0]);
                        }
                        
                        socketServer.Close();//关闭之前accept出来的和客户端进行通信的套接字
                        break;
                    }



                }
            }
            catch (Exception ex) 
            {
            }
        }
    }
}
